// phalanx operators.hpp.cu header file

// Copyright (c) 2011 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

// XXX: This is not good approach to call conversion operator implicitly.

#ifndef IG_PHALANX_MATH_DETAIL_OPERATORS_HPP_CU_ONCE_
#define IG_PHALANX_MATH_DETAIL_OPERATORS_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/seq/for_each.hpp>

#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>

#include <phalanx/type_traits/is_float.hpp.cu>
#include <phalanx/type_traits/is_integral.hpp.cu>

#include <phalanx/utility/enable_if.hpp.cu>

namespace phalanx
{

namespace math
{

namespace math_detail
{

#define LO_PHALANX_BINARY_OPERATOR_IMPL_( unused_r_, unused_, data_ ) \
  template < typename T, typename U > \
  PHALANX_CONFIG_DEFAULT_FUNCTION( true ) \
  typename lazy_enable_if< \
    ::boost::mpl::or_< is_float< T >, is_integral< T > >, \
    ::boost::mpl::if_c< BOOST_PP_TUPLE_ELEM( 3, 2, data_ ), bool, T > >::type \
  BOOST_PP_TUPLE_ELEM( 3, 1, data_ )( T x, const U &y ) \
  { return x BOOST_PP_TUPLE_ELEM( 3, 0, data_ ) static_cast< T >( y ); }

#define LO_PHALANX_BINARY_OPERATOR( seq_ ) \
  BOOST_PP_SEQ_FOR_EACH( LO_PHALANX_BINARY_OPERATOR_IMPL_, _, seq_ )

// XXX: These operators are require literal type at left hand to deduce type correctly.
LO_PHALANX_BINARY_OPERATOR(
  (( ==, _eq, true ))
  (( !=, _neq, true ))
  (( <=, _leq, true ))
  (( >=, _geq, true ))
  (( < , _le, true ))
  (( > , _gt, true ))

  (( + , _plus, false ))
  (( - , _sub, false ))
  (( * , _mul, false ))
  (( / , _div, false ))
  (( % , _mod, false ))

  (( +=, _splus, false ))
  (( -=, _ssub, false ))
  (( *=, _smul, false ))
  (( /=, _sdiv, false ))
  (( %=, _smod, false ))

  (( <<, _lsft, false ))
  (( >>, _rsft, false ))
  (( <<=, _slsft, false ))
  (( >>=, _srsft, false )) );

#undef LO_PHALANX_BINARY_OPERATOR
#undef LO_PHALANX_BINARY_OPERATOR_IMPL_

} // namespace math_detail

} // namespace math

} // namespace phalanx

#endif // IG_PHALANX_MATH_DETAIL_OPERATORS_HPP_CU_ONCE_

